#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

#define ARCHIVO "./test.txt"
#define VALOR_INICIAL 7
#define P_SUMADORES 3
#define P_RESTADORES 3
#define NUM_OPERACIONES 10

void esperar (int senhal);
void controlador (int senhal);

int main (int argc, char *argv[]) {
  FILE *fp;
  int pid_hijo;
  int aux, i;
  char *pNumOp;

  // Apertura del archivo.
  if ((fp = fopen(ARCHIVO, "w")) == NULL) {
    fprintf(stderr, "Error de apertura del archivo %s\n", ARCHIVO);
    exit(1);
  }

  // Escritura del valor inicial en el archivo...
  fprintf(fp, "%d", VALOR_INICIAL);
  fclose(fp);
  printf("Valor inicial: %d\n", VALOR_INICIAL);
  aux = VALOR_INICIAL + (P_SUMADORES - P_RESTADORES) * NUM_OPERACIONES;
  printf("Valor esperado: %d\n", aux);

  // Conversión de NUM_OPERACIONES a char*...
  pNumOp = (char*)malloc(sizeof(int));
  sprintf(pNumOp, "%d", NUM_OPERACIONES);

  // Se lanzan los sumadores...
  for (i = 0; i < P_SUMADORES; i++)
    switch (pid_hijo = fork()) {
    case 0:
      // Cada sumador recibe el nombre del archivo
      // y el número de incrementos a realizar
      execl("./exec/sumador", "sumador", ARCHIVO, pNumOp, NULL);
      break;
    }

  // Se lanzan los restadores...
  for (i = 0; i < P_RESTADORES; i++)
    switch (pid_hijo = fork()) {
    case 0:
      // Cada restador recibe el nombre del archivo
      // y el número de decrementos a realizar
      execl("./exec/restador", "restador", ARCHIVO, pNumOp, NULL);
      break;
    }

  free(pNumOp);

  // Se espera la terminación de los procesos...
  if (signal(SIGCHLD, esperar) == SIG_ERR) {
    fprintf(stderr, "No se esperó a un proceso.\n");
    exit(1);
  }

  // Manejo de Ctrol+C.
  if (signal(SIGINT, controlador) == SIG_ERR) {
    fprintf(stderr, "Terminación incorrecta.\n");
    exit(1);
  }

  while(1) // Bucle infinito de espera.
    pause(); // A la espera de Ctrl+C.
  
  return 0;
}

void esperar (int senhal) {
  int i;
  while (wait3(&i, WNOHANG, NULL) > 0);
}

void controlador (int senhal) {
  printf("\nCtrl+c capturada.\n");
  printf("Finalizando...\n\n");
  
  // Liberación de recursos...

  // Se muestra el contenido real del archivo...
  int valor;
  FILE *fp = fopen(ARCHIVO, "r");
  fscanf(fp, "%d", &valor);
  fclose(fp);
  printf("Valor real: %d\n", valor);

  sleep(1);
  printf("OK!\n");
  // Salida del programa.
  exit(0);
}
